﻿using IdentityModel;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Text;

namespace Stee.CAP8.ACL
{
    /// <summary>
    /// Extensions methods to configure Jwt Bearer Token, Authentication and Authorization
    /// </summary>
    public static class ServiceCollectionExtension
    {
        /// <summary>
        /// Configure Jwt Bearer Token verify options and authentication service.
        /// </summary>
        /// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
        /// <param name="configurationSection">The developer's <see cref="IConfigurationSection"/> to use.</param>
        /// <returns></returns>
        public static IServiceCollection AddACLAuthentication(this IServiceCollection serviceCollection, IConfigurationSection configurationSection)
        {
            if (serviceCollection == null)
            {
                throw new ArgumentNullException(nameof(serviceCollection));
            }

            if (configurationSection == null)
            {
                throw new ArgumentNullException($"Configuration Section can not be null! Object Name: {nameof(configurationSection)}");
            }

            var tokenValidationOption = new TokenValidationOption();
            configurationSection.Bind(tokenValidationOption);

            if (string.IsNullOrEmpty(tokenValidationOption.AuthenticateScheme))
            {
                throw new ArgumentNullException($"AuthenticateScheme can not be null! Object Name: {nameof(configurationSection)}");
            }
            if (tokenValidationOption.ValidateIssuer && string.IsNullOrEmpty(tokenValidationOption.ValidIssuer))
            {
                throw new ArgumentNullException($"ValidIssuer can not be null! Object Name: {nameof(configurationSection)}");
            }
            if (tokenValidationOption.ValidateAudience && string.IsNullOrEmpty(tokenValidationOption.ValidAudience))
            {
                throw new ArgumentNullException($"ValidAudience can not be null! Object Name: {nameof(configurationSection)}");
            }
            if (tokenValidationOption.ValidateIssuerSigningKey && string.IsNullOrEmpty(tokenValidationOption.IssuerSigningKey))
            {
                throw new ArgumentNullException($"IssuerSigningKey can not be null! Object Name: {nameof(configurationSection)}");
            }

            serviceCollection.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = tokenValidationOption.AuthenticateScheme;
                x.DefaultChallengeScheme = tokenValidationOption.AuthenticateScheme;
            })
            .AddJwtBearer(option =>
            {
                option.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = tokenValidationOption.NameClaim,
                    RoleClaimType = tokenValidationOption.RoleClaim,

                    ValidateIssuer = tokenValidationOption.ValidateIssuer,
                    ValidIssuer = tokenValidationOption.ValidateIssuer ? tokenValidationOption.ValidIssuer : string.Empty,
                    ValidateAudience = tokenValidationOption.ValidateAudience,
                    ValidAudience = tokenValidationOption.ValidateAudience ? tokenValidationOption.ValidAudience : string.Empty,
                    ValidateIssuerSigningKey = tokenValidationOption.ValidateIssuerSigningKey,
                    IssuerSigningKey = tokenValidationOption.ValidateIssuerSigningKey ? new SymmetricSecurityKey(Encoding.ASCII.GetBytes(tokenValidationOption.IssuerSigningKey)) : null
                };
            });

            return serviceCollection;
        }
        /// <summary>
        /// configure Authentication and Authorization middleware
        /// </summary>
        /// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
        /// <returns></returns>
        public static IApplicationBuilder UseACLAuthorize(this IApplicationBuilder app)
        {
            return app.UseAuthentication().UseAuthorization();
        }
    }
}
